		use16						; We are still Real-Mode so use 16-bits
		org	0					; Load in address 7C00h

		jmp	Start					; Skip BIOS parameter block
		;nop                                            ; Because the BPB begins 3 bytes from the start, add a byte (2 bytes + 1 byte)

;=============================================================================
;
;
;               BIOS PARAMETER BLOCK
;
;
;=============================================================================
bpbOEM			db "VEDIA OS"
bpbBytesPerSector	dw 512					;
bpbSectorsPerCluster	db 1					;
bpbReservedSectors	dw 1					;
bpbNumberOfFATs 	db 2					; There are always to FAT on a disk
bpbRootEntries		dw 224					; Total number of directories
bpbTotalSectors 	dw 2880 				; There are 2880 sectors on a disk
bpbMedia		db 0xF0 				;
bpbSectorsPerFAT	dw 9					;
bpbSectorsPerTrack	dw 18					;
bpbHeadsPerCylinder	dw 2					;
bpbHiddenSectors	dd 0					;
bpbTotalSectorsBig	dd 0					;
bsDriveNumber		db 0					;
bsUnused		db 0					;
bsExtBootSignature	db 0x29 				;
bsSerialNumber		dd 0x00000000				;
bsVolumeLabel		db "VEDIAFLOPPY"			;
bsFileSystem		db "FAT12   "				;

;=============================================================================
;               NAME:           Print
;               DESCRIPTION:    Prints string to screen.
;               IN:             SI = string
;               OUT:            Nothing
;=============================================================================

Print:
		lodsb
		or	al, al
		jz	.Exit
		mov	ah, 0x0E
		int	10h
		jmp	Print
	.Exit:
		ret

AbsoluteSector db 0x00
AbsoluteHead   db 0x00
AbsoluteTrack  db 0x00

;=============================================================================
;               NAME:           ClusterLBA
;               DESCRIPTION:    Converts CHS to LBA
;                               LBA = (cluster - 2) * sectors per cluster
;               IN:             N/A
;               OUT:            N/A
;=============================================================================

ClusterLBA:
		sub	ax, 0x0002				; zero base cluster number
		xor	cx, cx
		mov	cl, byte [bpbSectorsPerCluster] 	; convert to byte to word
		mul	cx
		add	ax, word [datasector]			; base data sector
		ret

;=============================================================================
;               NAME:           LBACHS
;               DESCRIPTION:    Converts LBA to CHS
;               IN:             AX -> LBA Address to convert
;               OUT:            N/A
;
;               absolute sector = (logical sector / sectors per track) + 1
;               absolute head   = (logical sector / sectors per track) MOD number of heads
;               absolute track  =  logical sector / (sectors per track * number of heads)
;=============================================================================

LBACHS:
		xor	dx, dx					; prepare DX:AX for operation
		div	word [bpbSectorsPerTrack]		; calculate
		inc	dl					; adjust for sector 0
		mov	byte [AbsoluteSector], dl
		xor	dx, dx					; prepare DX:AX for operation
		div	word [bpbHeadsPerCylinder]		; calculate
		mov	byte [AbsoluteHead], dl
		mov	byte [AbsoluteTrack], al
		ret

;=============================================================================
;               NAME:           ReadSectors
;               DESCRIPTION:    Reads a series of sectors
;               IN:             CX -> Number of sectors to read
;                               AX -> Starting sector
;                               ES:BX -> Buffer to read to
;               OUT:            N/A
;=============================================================================

ReadSectors:
	.MAIN:
		mov	di, 0x0005				; five retries for error
	.SECTORLOOP:
		push	ax
		push	bx
		push	cx
		call	LBACHS					; convert starting sector to CHS
		mov	ah, 0x02				; BIOS read sector
		mov	al, 0x01				; read one sector
		mov	ch, byte [AbsoluteTrack]		; track
		mov	cl, byte [AbsoluteSector]		; sector
		mov	dh, byte [AbsoluteHead] 		; head
		mov	dl, byte [bsDriveNumber]		; drive
		int	0x13					; read disk
		jnc	.SUCCESS				; if no error, continue
		xor	ax, ax					; function 0 - reset disk
		int	0x13					; invoke BIOS to reset disk
		dec	di
		pop	cx
		pop	bx
		pop	ax
		jnz	.SECTORLOOP				; attempt to read again
		int	0x18
	.SUCCESS:
		mov	si,ProgressMsg
		call	Print
		pop	cx
		pop	bx
		pop	ax
		add	bx, word [bpbBytesPerSector]		; queue next buffer
		inc	ax					; queue next sector
		loop	.MAIN					; read next sector
		ret


;=============================================================================
;
;
;               BOOTLOADER (STAGE 1) ENTRY POINT
;
;
;=============================================================================

Start:

		; Setup the segments to ensure that they are they are 07C0.
		; Remember that we ORG 7C00. This means all addresses
		; are based from 0:7C00, whose linear address is 07C0:000.

		cli						; disable interrupts
		mov	ax, 0x07C0				; setup segments
		mov	ds, ax
		mov	es, ax
		mov	fs, ax
		mov	gs, ax

		; create stack

		mov	ax, 0x0000
		mov	ss, ax
		mov	sp, 0xFFFF
		sti

	;======================================================================
	; Load root directory table
	;======================================================================

	LoadRoot:

		; compute size of root directory and store in CX
		; root directory size = (Boot entries * 32) / Bytes per sector

		xor	cx, cx
		xor	dx, dx
		mov	ax, 0x0020				; 32 byte directory entry
		mul	word [bpbRootEntries]			; total size of directory
		div	word [bpbBytesPerSector]		; sectors used by directory
		xchg	ax, cx

		; compute location of root directory and store in AX

		mov	al, byte [bpbNumberOfFATs]		; number of FATs
		mul	word [bpbSectorsPerFAT] 		; sectors used by FATs
		add	ax, word [bpbReservedSectors]		; sdjust for bootsector
		mov	word [datasector], ax
		add	word [datasector], cx

		; read root directory into memory (7C00:0200)

		mov	bx,0x0200				; copy root dir above bootcode
		call	ReadSectors

	;======================================================================
	; Find Stage 2 loader
	;======================================================================

		; browse root directory for binary image

		mov	cx, word [bpbRootEntries]		; the number of entries. If we reach 0, file was not found
		mov	di,0x0200				; root directory was loaded here
	.Loop:
		push	cx
		mov	cx,11					; eleven character name
		mov	si,ImageName				; compare the 11 bytes withg the name of the file
		push	di
		rep	cmpsb					; test for entry match
		pop	di
		je	LoadFat 				; they match, so begin loading FAT
		pop	cx
		add	di,32					; they don't match, so go to next entry (32 bytes)
		loop	.Loop
		jmp	Failure

	;======================================================================
	; Load FAT
	;======================================================================

	LoadFat:

		; save starting cluster of boot image

		mov	si, CrlfMsg
		call	Print
		mov	dx, word [di+0x001A]
		mov	word [cluster],dx			; file's first cluster

		; compute size of FAT and store in CX

		xor	ax, ax
		mov	al, byte [bpbNumberOfFATs]		; number of FATs
		mul	word [bpbSectorsPerFAT] 		; sectors used by FATs
		mov	cx, ax

		; compute location of FAT and store in AX

		mov	ax, word [bpbReservedSectors]		; adjust for boosector

		; read FAT into memory (7C00:0200)

		mov	bx,0x0200				; copy FAT above bootcode
		call	ReadSectors

		; read image file into memory (0050:0000)

		mov	si,CrlfMsg
		call	Print
		mov	ax,0x0050
		mov	es,ax					; destination for image
		mov	bx,0x0000				; destination for image
		push	bx

	;======================================================================
	; Load Stage 2
	;======================================================================

	LoadImage:

		mov	ax, word [cluster]			; cluster to read
		pop	bx					; buffer to read into
		call	ClusterLBA				; convert cluster to LBA
		xor	cx,cx
		mov	cl,byte [bpbSectorsPerCluster]		; sectors to read
		call	ReadSectors
		push	bx

		; Compute next cluster
     
		mov	ax, word [cluster]			; identify current cluster
		mov	cx, ax					; copy current cluster
		mov	dx, ax					; copy current cluster
		shr	dx, 0x0001				; divide by two
		add	cx, dx					; sum for (3/2)
		mov	bx, 0x0200				; location of FAT in memory
		add	bx, cx					; index into FAT
		mov	dx, word [bx]				; read two bytes from FAT
		test	ax, 0x0001
		jnz	.OddCluster
	  
	.EvenCluster:
     
		and	dx,0000111111111111b			; take low twelve bits
		jmp	.Done
	 
	.OddCluster:
     
		shr	dx,0x0004				; take high twelve bits
	  
	.Done:
     
		mov	word [cluster], dx			; store new cluster
		cmp	dx,0x0FF0				; test for end of file
		jb	LoadImage
	  
	Complete:

		mov	si,LoadingMsg
		call	Print
		push	word 0x0050
		push	word 0x0000
		retf
	  
	Failure:
     
		mov	si,FailureMsg
		call	Print
		mov	ah,0x00
		int	0x16					; await keypress
		int	0x19					; warm boot computer


;=============================================================================
;
;
;               BOOTLOADER (STAGE 1) DATA
;
;
;=============================================================================
datasector	dw	0x0000
cluster 	dw	0x0000
ImageName	db	'STAGE2  BIN'
CrlfMsg 	db	13,10,0
LoadingMsg	db	'Loading Stage-2 Loader',13,10,0
ProgressMsg	db	'.',0
FailureMsg	db	13,10,'ERROR: STAGE2.BIN MISSING. Press any key to reboot',0


		times 510-($-$$) db 0
		dw	0xAA55